using System;
using System.Reflection;
using DDD.Framework;
using NUnit.Framework;

namespace Specifications.DDD.Framework.DomainEntitySpecs
{
    [TestFixture]
    public class WhenCreatingANewEntity
    {
        [Test]
        public void ShouldAlsoBeADomainObject()
        {
            Type domainBase = typeof (DomainEntity<int>).BaseType;
            Assert.IsTrue(domainBase.Equals(typeof (DomainObject)), "Entities should be generic domain objects.");
        }

        [Test]
        public void ShouldNotBeAbleToInstantiateDomainEntityDirectly()
        {
            bool isEntityAbstract = typeof (DomainEntity<int>).IsAbstract;
            Assert.IsTrue(isEntityAbstract, "Cannot directly instantiate a generic entity.");
        }

        [Test]
        public void ShouldBeAbleToSpecifyTheGenericTypeUniqueIdentification()
        {
            FooEntity<int> entity = new FooEntity<int>();
            Assert.IsTrue(typeof (int).IsAssignableFrom(entity.Identity.GetType()), "The Generic type should be identity.");
        }

        [Test]
        public void ShouldHaveIdentityFieldForUniqueIdentification()
        {
            PropertyInfo identityFieldPropertyInfo = GetIdentityFieldFromDomainEntity();
            Assert.IsNotNull(identityFieldPropertyInfo, "Entity should have an identity field for unique identification.");
        }

        [Test]
        public void ShouldNotBeAbleToOverwriteIdentityFieldSinceUniquenessIsProvidedByTheSystem()
        {
            PropertyInfo identityFieldPropertyInfo = GetIdentityFieldFromDomainEntity();
            Assert.IsFalse(identityFieldPropertyInfo.CanWrite, "The identity cannot be directly set.");
        }

        private static PropertyInfo GetIdentityFieldFromDomainEntity()
        {
            return typeof (DomainEntity<int>).GetProperty("Identity");
        }
    }

    internal class FooEntity<UniqueKeyType> : DomainEntity<UniqueKeyType>
    {

    }
}